package com.ruoyi.system.xcenter.utils;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;


/***
 * RSA公钥/私钥/签名工具包
 * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
 * 由于非对称加密速度极其缓慢，一般文件不使用它来加密而是使用对称加密，<br/>
 * 非对称加密算法可以用来对对称加密的密钥加密，这样保证密钥的安全也就保证了数据的安全
 * @author 杨磊
 * @Date 2014-5-20
 * @version 1.0
 */
public class RSAUtil {

    /** *//**
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";

    /** *//**
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /** *//**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    private static final int MAX_DECRYPT_BLOCK = 128;


    private static final String PUBLIC_KEY ="publicKey";
    private static final String PRIVATE_KEY ="privateKey";

    /** *//**
     * <p>
     * 用私钥对信息生成数字签名
     * </p>
     *
     * @param content 已加密数据
     * @param privateKey 私钥(BASE64编码)
     *
     * @return
     * @throws Exception
     */
    public static String sign(String content, String privateKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        byte[] data = content.getBytes(Charset.forName("UTF-8"));
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        RSAPrivateKey privateK = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64.encodeBase64String(signature.sign());
    }

    //ASN1Primitive asn1Prime = new ASN1InputStream(decoded).readObject();
    //
    //	org.bouncycastle.asn1.pkcs.RSAPublicKey rsaPub = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(asn1Prime);
    //



    /** *//**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param privateKey 源数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey(String content, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        byte[] data = content.getBytes(Charset.forName("UTF-8"));
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        RSAPrivateKey privateK = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return  Base64.encodeBase64String(encryptedData);
    }

    public static String encryptByPublicKey(String content, String publicKey) throws Exception {
        byte[] data = content.getBytes(Charset.forName("UTF-8"));
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return Base64.encodeBase64String(encryptedData);

    }

    /**
     * MQ解密不可用
     * @param dataStr
     * @param privateKey
     * @return
     * @throws Exception
     */
    @Deprecated
    public static String decryptByPrivateKey(String dataStr, String privateKey) throws Exception {
        byte[] data = Base64.decodeBase64(dataStr);
        // 得到私钥
        byte[] keyBytes = Base64.decodeBase64(privateKey.getBytes());
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 解密数据
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        // SealedObject obj = new SealedObject(data, cipher);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解�?
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        //byte[] messageBytes = (byte[]) obj.getObject(cipher);
        return new String(decryptedData);
    }

    public static String decryptByPublicKey(String dataStr, String publicKey) throws Exception {
        byte[] data = Base64.decodeBase64(dataStr);
        // 得到私钥
        byte[] keyBytes = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        // SealedObject obj = new SealedObject(data, cipher);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解�?
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        //byte[] messageBytes = (byte[]) obj.getObject(cipher);
        return new String(decryptedData);
    }



    public static void main1(String[] args) {
        try {
//            Map<String,String> keyMap = RSAUtil.genKey();
//            System.out.println(JSONObject.toJSONString(keyMap));
//            String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCf4rRqRqemOR8dt09Yi99Crp3bT6iEwBG5DT0jeQi+odfVLllwfXilvIUSS8QcSOrDe48Z6VZrVkUkvWYm5NbIb4CzfdswGxf0MVSlGtpeAJOY6+ICIDnVnE8UlV2ZjWAO9pw+rEZM6pIx4pxfHHSdFFgRSiGQl0/11SMYhj7sewIDAQAB";
//            String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ/itGpGp6Y5Hx23T1iL30KundtPqITAEbkNPSN5CL6h19UuWXB9eKW8hRJLxBxI6sN7jxnpVmtWRSS9Zibk1shvgLN92zAbF/QxVKUa2l4Ak5jr4gIgOdWcTxSVXZmNYA72nD6sRkzqkjHinF8cdJ0UWBFKIZCXT/XVIxiGPux7AgMBAAECgYEAm22p8b6p77+L7jlrmyquaYaS0saHjjWhhQHHs5pP0/JFfWpHbEGtbYDs5DJffRetkUemf4wEhOgi42pzyc+gs0EHiuzo5DNoixit16RhV43aAAFupHFTtYL80rUiJPuN/xu9lII9Jvw8Cj2RjB+xu0S/LCUFLoCJTQ6MCZzvreECQQDjsoN8+2oISE7N9e43NQyX4hg0JAsiZ8zp3eeTpoXgyDeamXVqxz+OK799Sh08vYW/jeMd/ANeGXaw/yHG9+vjAkEAs8JfyT8tdfQQpz/zIRq0yE/7QmAqDhPXPwWRxoYFqO7Ang81np2X+8hDoip2VKM4o+YBwy+PFL6SI8585zaQiQJAJhUIOtIN1N7LF1VnhyI/PfPZmnbgydtUgVTU03QJdiPmcNvzsG0sqwmUGE9Z/nuwL+56Ktyob4eQu1+gdZengwJAEWaXbxu2gtyFYCtIlcPIDDvxzpMQfxxckbUwT09Z7OhvrN08C4al17GjGmeR3M+QBA2XzhUkfJWV//FVFeyqQQJAai+t7CNJlztZ3KYOMBwCtQYmU6Uw7amC5YkxX0IOj8gneFUziCqVQRV5nKKmFFeXn8XjSkl3SDta7A/ducAnrA==";

            String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCAcCuoECB6ebbNyeDD1HfTUL5BXwhUURD0FK0qCk48zjf9FwiWzuZlSB+lKPWmwyB7efrNJold/JSNI1WHXCiT/oOAXBFt7HRDZqkuQUmJhMYdRJ/rWwtHxA8fe2x31ywPbE6NyrVCKM6Ld7+wNDnjJC1HEOHRpDaY13DAhab0UQIDAQAB";
            String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIBwK6gQIHp5ts3J4MPUd9NQvkFfCFRREPQUrSoKTjzON/0XCJbO5mVIH6Uo9abDIHt5+s0miV38lI0jVYdcKJP+g4BcEW3sdENmqS5BSYmExh1En+tbC0fEDx97bHfXLA9sTo3KtUIozot3v7A0OeMkLUcQ4dGkNpjXcMCFpvRRAgMBAAECgYAesjBM32XTv6kn77qvMuVcdKyz1PGZrTI/E337UTE3qRWKgGnGGTbJN/6QK4TiUTo/KHz/cNldxBMA1FQJoMX1mbH6Eoo8bRHCQfmFknG4OpnWVk7BPQ6fu950pjcwEcwCIHq9uh6B4HtgTLcLio0De7WrqH3p+qgXR++qSIgTDQJBAMmbEk1eSGt2+KupGez7uR+6/qe2zb7ktoS6FcTZGn/Qv+dvhG2LMmKfAHpatiM3AgTDVdjKJ0Ygs2w6s+jMYrMCQQCjF2g2zbTaszK1cmYEuBLHoYEJH9f4Xf6AKq539qa6KAo6T5iXQ6girHcyCJx8Yke8h1K+Gx9um8Gwl+YR2z7rAkAxkrsOYTenjSqac0tXtZIQ1ldWACJZZT3oJyXBMK1ObpMxon9KvGaYT4a7j2CoChep+io604KSwOm9nDWu8cr3AkEAkRB/5MdCB4l/ID+aGLZ2FdVExg3p9wP8HJpaR2A/2rNErasg6eMHCZhoCTv5nPV6I2omoevUIHkwZlgmD1n5cwJAQ7xYThmw8fdh2IeuXU7bCRpRSo2zTkM1pMyf5YpJIMuZ6XPVJLxB5x6B6tyZLSc7CZkT1SGA2nSmfYb4Ka0Vig==";


            JSONObject dataInfo = new JSONObject();
            dataInfo.put("say","aaa");
            dataInfo.put("say1","aaa");

            JSONObject message = new JSONObject();
            message.put("requestId",11182827282L);
            message.put("timestamp", DateUtils.dateTimeNow());
            message.put("parkpotId", "aasdasdasd");
//            String dataStr = RSAUtil.encryptByPublicKey(dataInfo.toJSONString(),publicKey);
            String dataStr = RSAUtil.encryptByPrivateKey(dataInfo.toJSONString(),privateKey);
            String dataStr2 = "Bjh0uRM/GaWNv4JUgOcwGn5P1b/VA3oFV980swXZoDsvKBCZQeU/uA1MhWnI7UJ/99DDNJvZbUdrx6KG1nD/SHQnm4GIREeU2josJzp+hMfnVx54O+yvBNPJx1VzYeDHO0UCJQ0hVvvVduhQ3dYqOBJZdlQMIWU4yZH7D184E0I=";
            System.out.println(dataStr);
            message.put("data",dataStr);
            message.put("sign",RSAUtil.sign(dataStr,privateKey));
            System.out.println("拼接后的数据:"+message.toJSONString());

            try {
                //check sign
//                JSONObject deData = JSONObject.parseObject(RSAUtil.decryptByPrivateKey(message.getString("data"),privateKey));
                JSONObject deData = JSONObject.parseObject(RSAUtil.decryptByPublicKey(message.getString("data"),publicKey));
                System.out.println("解密后的数据:"+deData.toJSONString());
            }catch (Exception e){
                e.printStackTrace();
            }


        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public static void main(String[] args) throws Exception {
//        java.security.Security.addProvider(
//                new org.bouncycastle.jce.provider.BouncyCastleProvider()
//        );
        String data = "MQcXGhqD7Rn1q5sUyzzLOuMhTFpaHGjyqgK3wxW31/O50x8FFRGcERPC4TZi9i3v6RVfDSk3LX2jXqT/2RV87SMJilsSjf7arxcrePdSOU01BBk8Abhs9yCWwitFG6xlr64DeDw8hn3bwXX0Bik46axoG4ncKwrZPBYkl1tNego=";
        String pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJzfIKmsOBbzlAKXa7F8Ud0cOnCPo8Lug+g2aOK7DTuP7OqU2f57bA1qNnLuAGRxaRj1sRHdl5TplVFJAY5lw3ZU3o4To8LK6dVYdAipVvEHpDW3zsEwG2V+SVnA/MPjg2X3ryoNrRnDeTywj89AD3XkKd8gW4gUazhA0l3dGQ0QIDAQAB";
        String priKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAInN8gqaw4FvOUApdrsXxR3Rw6cI+jwu6D6DZo4rsNO4/s6pTZ/ntsDWo2cu4AZHFpGPWxEd2XlOmVUUkBjmXDdlTejhOjwsrp1Vh0CKlW8QekNbfOwTAbZX5JWcD8w+ODZfevKg2tGcN5PLCPz0APdeQp3yBbiBRrOEDSXd0ZDRAgMBAAECgYAT+CUgBkdYhV6dfqS2/f3RkWkx1mo0uHNtQ6tj5M7uD3vVRNF7358rGK97L17Fah3KICUJOPMf0hUEMEOlaBRqtrOn1g7ApnFa4drNNYMG9ccuWsO2QKgnzZmXDJfbmmgxtK/fDvF7aznV73uEHWB3IU6UwcfUJjIoAyUPlBHyxQJBAO1UsyzBfuWRt6FxwD87WSoOFlTJavQlw2RMTSND5yxyqP4vmWp5FZbIvpFgsRiVZo9YF4I41uY8/HbwxobFu3cCQQCUpQMW7PQ8Ta28xbXEMFFzbMrTzoOCeiQEkQOz1RTa5R1T4bca0XvY3jXTlxv8gaD86R8os63uNy8axoaA3hf3AkEA2Ml9wWweVeT9L+OQEDJOCDRGAbzajZnRGVT5QTVNfTRfWZBxOujP56QHLxR7sFEIFfgJwVHaOwWKN7tIHOORkQJARx3Ho6FMnMlhVQ6Wjz26ymmDhOCqBLPhJZon1lMc/jld1bMJAri08yYlRI1oY1+1oSr7sGJ+1ZjrXXkcAu2/MwJAGtRKZ5wrqGmKx2BMZ0xqNtZd0qGbitNi9EE8wQ+92AP9rh8t2uQfderF24ApaUXEMYGiFKQoM2lDzsIuliWkGw==";
        String s = RSAUtil.sign(data, priKey);
        System.out.println(s);
//        String d = RSAUtil.decryptByPrivateKey(data, priKey);
//        System.out.println(d);
        RSA rsa = SecureUtil.rsa(cn.hutool.core.codec.Base64.decode(priKey), cn.hutool.core.codec.Base64.decode(pubkey));
        rsa.encrypt("dd",KeyType.PrivateKey);
        byte[] decrypt = rsa.decrypt(data, KeyType.PrivateKey);
        System.out.println(new String(decrypt));
    }
}
